#include <iostream>
#include <string>
#include <vector>
#include <cstdio>
#include <pthread.h>
#include <unistd.h>

#define NUM 5

int tickets = 5000;  // 多线程模拟抢票
pthread_mutex_t lock;   // 全局定义一个动态分配互斥量

class threadData
{
public:
    threadData(int number)
    {
        _threadName = "thread-" + std::to_string(number);
    }
public:
    std::string _threadName;
};

void *getTicket(void *args)
{
    threadData *td = static_cast<threadData*>(args);
    const char *name = td->_threadName.c_str();

    while (true)
    {
        pthread_mutex_lock(&lock);  // 申请锁成功,才能往后执行,否则阻塞等待
        if (tickets > 0)
        {
            usleep(1000);
            printf("who: %s get a ticket: %d\n", name, tickets);
            --tickets;
            pthread_mutex_unlock(&lock);  // 释放锁,防止造成死锁
        }
        else 
        {
            pthread_mutex_unlock(&lock);  // 释放锁,防止造成死锁
            break;
        }
        usleep(1);  
        // 模拟抢到票后的后续动作
        // 否则由于该线程切换成本低, 还是该线程申请锁成功, 造成其它线程饥饿
    }
    printf("%s ... quit\n", name);
    return nullptr;
}

int main()
{   
    pthread_mutex_init(&lock, nullptr);  // 初始化互斥量
    std::vector<pthread_t> tids;
    std::vector<threadData *> tds;    

    for (int i = 1; i <= NUM; ++i)
    {
        pthread_t tid;
        threadData *td = new threadData(i);
        tds.push_back(td);
        pthread_create(&tid, nullptr, getTicket, tds[i-1]);
        tids.push_back(tid);
    }

    for (auto tid : tids)
    {
        pthread_join(tid, nullptr);
    }

    pthread_mutex_destroy(&lock);  // 销毁互斥量, 动态分配的互斥量需要销毁
    // 注意: 已经销毁的互斥量, 要确保后面不会有线程再尝试加锁

    for (auto td : tds)
    {
        delete td;
    }

    return 0;
}